﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicMaker
{
    public class MusicLoader
    {
        private string text;
        private int idx;
        public Music load(string txt)
        {
            Music music;
            text = txt;
            music = readMusic();
            return music;
        }
        private Music readMusic()
        {
            Music music = new();
            eatSpace(); readWord();//读入"music"
            eatSpace(); getChar();//读入"("
            eatSpace();
            music.title = readStr();
            eatSpace(); getChar();//读入","
            eatSpace();
            music.speed = int.Parse(readNum());
            eatSpace(); getChar();//读入")"
            eatSpace(); getChar();//读入"["
        beginReadChannel:
            eatSpace();
            switch (curChar())
            {
                case 'c':
                    music.channels.Add(readChannel());
                    goto beginReadChannel;
                default:
                    break;
            }
            eatSpace(); getChar();//读入"]"
            return music;
        }
        private Channel readChannel()
        {
            Channel channel = new();
            eatSpace(); readWord();//读入"channel"
            eatSpace(); getChar();//读入"("
            eatSpace();
            channel.InstrumentId = int.Parse(readNum());
            eatSpace(); getChar();//读入","
            eatSpace();
            channel.Volume = int.Parse(readNum());
            eatSpace(); getChar();//读入")"
            eatSpace(); getChar();//读入"["
        beginReadChannel:
            eatSpace();
            switch (curChar())
            {
                case 'p':
                    channel.PatternList.Add(readPattern());
                    goto beginReadChannel;
                default:
                    break;
            }
            eatSpace(); getChar();//读入"]"
            return channel;
        }

        private Pattern readPattern()
        {
            Pattern pattern = new();
            eatSpace(); readWord();//读入"pattern"
            eatSpace(); getChar();//读入"("
            eatSpace();
            pattern.Name = readStr();
            eatSpace(); getChar();//读入","
            eatSpace();
            pattern.BeginTime = int.Parse(readNum());
            eatSpace(); getChar();//读入")"
            eatSpace(); getChar();//读入"["
        beginReadPattern:
            eatSpace();
            switch (curChar())
            {
                case '<':
                    pattern.NoteList.Add(readNote());
                    goto beginReadPattern;
                default:
                    break;
            }
            eatSpace(); getChar();//读入"]"
            return pattern;
        }

        private Note readNote()
        {
            Note note = new();
            eatSpace(); getChar();//读入"<"
            eatSpace();
            note.Pitch = int.Parse(readNum());
            eatSpace(); getChar();//读入","
            note.Begin = int.Parse(readNum());
            eatSpace();
            eatSpace(); getChar();//读入","
            eatSpace();
            note.Time = int.Parse(readNum());
            eatSpace(); getChar();
            eatSpace();
            note.Force = int.Parse(readNum());
            eatSpace(); getChar();//读入">"
            return note;
        }
        //读入整数
        private string readNum()
        {
            string s = "";
            while('0' <= curChar() && curChar() <= '9')
            {
                s += getChar();
            }
            return s;
        }

        //读入带引号的字符串的内容
        private string readStr()
        {
            string str = "";
            getChar();//读入单引号
            while (curChar() != '\"') str += getChar();
            getChar();//读入单引号
            return str;
        }

        //读入一个不带引号的单词
        private string readWord()
        {
            string s = "";
            while(isNumberOrAlphaOrUnderline(curChar()))
            {
                s += getChar();
            }
            return s;
        }

        //是否是数字、字符或下划线
        private bool isNumberOrAlphaOrUnderline(char ch)
        {
            return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == ' ';
        }
        private char curChar()
        {
            return text[idx];
        }

        private char nextChar()
        {
            return text[idx + 1];
        }

        private char getChar()
        {
            return text[idx++];
        }

        private void eatSpace()
        {
            char ch = text[idx];
            if (ch == ' ' || ch == '\n' || ch == '\t')
                getChar();
        }
    }
}
